package base;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class Utils {
    private static HashMap<String,String> nonAmbiguityTypes;

    public static String createClass(String tableName, String packagePath, List<String> fields, List<String> types){
        prepare(types);
        StringBuilder sb = new StringBuilder();
        if(packagePath != null && packagePath.length() != 0){
            sb.append("package ");
            sb.append(packagePath);
            sb.append(";\n");
        }
        appendImports(sb, types);
        if(sb.length() != 0) {
            sb.append('\n');
        }
        sb.append("public class ");
        sb.append(getClassName(tableName));
        sb.append(" {\n");
        appendAttributes(sb, fields, types);
        appendMethods(sb, fields, types);
        sb.append('}');
        return sb.toString();
    }

    public static void prepare(List<String> types){
        nonAmbiguityTypes = new HashMap<>();
        for(String s : types){
            String[] split = s.split("\\.");
            String s1 = split[split.length - 1];
            if(split.length > 1){
                nonAmbiguityTypes.put(s1,s.substring(0,s.length() - s1.length() - 1));
            }
        }
        for(String s : types){
            String[] split = s.split("\\.");
            String s1 = split[split.length - 1];
            String s2 = nonAmbiguityTypes.get(s1);
            if(s2 != null && split.length > 1 && !s.substring(0,s.length() - s1.length() - 1).equals(s2)){
                nonAmbiguityTypes.remove(s1);
            }
        }
    }

    public static void appendMethods(StringBuilder sb, List<String> fields, List<String> types){
        Iterator<String> fieldIt = fields.iterator();
        Iterator<String> typeIt = types.iterator();
        while (fieldIt.hasNext()){
            String field = fieldIt.next();
            String type = typeIt.next();

            sb.append('\n');
            appendSpaces(sb, 4);
            sb.append("public void set");
            String attrName = getAttrName(field);
            char[] chars = attrName.toCharArray();
            chars[0] = (chars[0] + "").toUpperCase().charAt(0);
            sb.append(chars);
            sb.append('(');
            sb.append(getSimpleType(type));
            sb.append(' ');
            sb.append(attrName);
            sb.append(") {\n");
            appendSpaces(sb, 8);
            sb.append("this.");
            sb.append(attrName);
            sb.append(" = ");
            sb.append(attrName);
            sb.append(";\n");
            appendSpaces(sb, 4);
            sb.append("}\n");

            sb.append('\n');
            appendSpaces(sb, 4);
            sb.append("public ");
            sb.append(getSimpleType(type));
            sb.append(" get");
            sb.append(chars);
            sb.append("() {\n");
            appendSpaces(sb, 8);
            sb.append("return ");
            sb.append(attrName);
            sb.append(";\n");
            appendSpaces(sb, 4);
            sb.append("}\n");
        }
    }

    public static void appendImports(StringBuilder sb, List<String> types){
        HashSet<String> set = new HashSet<>();
        boolean isFirst = true;
        for(String type : types){
            String[] split = type.split("\\.");
            if(split.length > 1 && !(split[0].equals("java") && split[1].equals("lang"))){
                if(isFirst){
                    if(sb.length() > 0){
                        sb.append('\n');
                    }
                    isFirst = false;
                }
                if(set.contains(type)){
                    continue;
                }
                sb.append("import ");
                sb.append(type);
                sb.append(";\n");
                set.add(type);
            }
        }
    }

    public static void appendAttributes(StringBuilder sb, List<String> fields, List<String> types){
        Iterator<String> fieldIt = fields.iterator();
        Iterator<String> typeIt = types.iterator();
        while (fieldIt.hasNext()){
            String field = fieldIt.next();
            String type = typeIt.next();
            appendSpaces(sb, 4);
            sb.append("private ");
            sb.append(getSimpleType(type));
            sb.append(' ');
            sb.append(getAttrName(field));
            sb.append(";\n");
        }
    }

    public static void appendSpaces(StringBuilder sb, int count){
        for(int i = 0; i < count; ++i){
            sb.append(' ');
        }
    }

    public static String getSimpleType(String s){
        String[] split = s.split("\\.");
        if(!nonAmbiguityTypes.containsKey(split[split.length - 1])){
            return s;
        }
        return split[split.length - 1];
    }

    public static String getAttrName(String s){
        char[] chars = s.toCharArray();
        if(!checkAllUppercase(s)){
            chars[0] = (chars[0] + "").toLowerCase().charAt(0);
        }
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < chars.length; ++i){
            if(chars[i] == '_'){
                chars[i + 1] = (chars[i + 1] + "").toUpperCase().charAt(0);
            } else {
                sb.append(chars[i]);
            }
        }
        return sb.toString();
    }

    public static String getClassName(String s){
        char[] chars = s.toCharArray();
        chars[0] = (chars[0] + "").toUpperCase().charAt(0);
        String[] split = s.split("_");
        if(split.length == 1){
            return new String(chars);
        }
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < chars.length; ++i){
            if(chars[i] == '_'){
                chars[i + 1] = (chars[i + 1] + "").toUpperCase().charAt(0);
            } else {
                sb.append(chars[i]);
            }
        }
        return sb.toString();
    }

    public static String getArrayTypeBySymbol(String symbol){
        if(symbol.equals("[B")){
            return "java.lang.Byte[]";
        } else if(symbol.equals("[C")){
            return "java.lang.Character";
        } else if(symbol.equals("[I")){
            return "java.lang.Integer";
        } else if(symbol.equals("[S")){
            return "java.lang.Short";
        }
        return symbol;
    }

    public static boolean saveClass(String aClass, String path){
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path);
            byte[] bytes = aClass.getBytes("UTF-8");
            fos.write(bytes);
        } catch (Exception e){
            return false;
        } finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    return false;
                }
            }
        }
        return true;
    }

    public static String getFieldSql(String table, int dbType){
        if(dbType == 0){
            return "select * from " + table + " limit 1";
        } else if(dbType == 1){
            return "select * from " + table + " where 1=2";
        }
        return null;
    }

    public static boolean checkAllUppercase(String s){
        for(char ch : s.toCharArray()){
            if(ch >= 97 && ch <= 122){
                return false;
            }
        }
        return true;
    }
}
